package com.kj.misc.domain;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
@NoArgsConstructor
public class MiscFetcherConfig {
	
    @XmlElement(name="fetcher")
	@Getter @Setter
	private List<FetcherEntry> fetchers = Lists.newArrayList();
    
	public List<String> getKeys() {
		
		List<String> keys = Lists.newLinkedList();
		
		fetchers.forEach(fe->{
			fe.getValues().forEach(ve->{
				String key = key(fe, ve);
				keys.add(key);
			});			
		});
		
		return keys;
	}
	
	public Optional<String> getParameter(String valuekey, String parameterKey) {
		
		for(FetcherEntry fe : fetchers) {
			for(ValueEntry ve : fe.getValues()) {
				String key = key(fe, ve);
				if(key.equals(valuekey)) {
					
					ParameterManager pw = ParameterManager.at(ve);
					return Optional.of(pw.getOrDefault(parameterKey, ""));
				}
			}
		}
		
		return Optional.empty();
	}
	
	public boolean updateParameter(String valuekey, String parameterKey, String parameterValue) {
		
		//FetcherEntry f = null;
		ValueEntry v = null;
		boolean found = false;
		
		for(FetcherEntry fe : fetchers) {
			for(ValueEntry ve : fe.getValues()) {
				String key = key(fe, ve);
				if(key.equals(valuekey)) {
					//f = fe;
					v = ve;
					found = true;
					break;
				}
			}
			if(found) {
				break;
			}
		}
		
		if(found) {
			
			ParameterManager pw = ParameterManager.at(v);
			pw.setValue(parameterKey, parameterValue);
			v.setParameters(pw.toString());
		}
		
		return found;

		
	}
	
	
	@XmlAccessorType(XmlAccessType.FIELD)
	@XmlRootElement
	@NoArgsConstructor
	public static class FetcherEntry {
		
		@XmlAttribute
		@Getter @Setter
		private String name = "Fetcher" + System.currentTimeMillis();
		
		@XmlAttribute
		@Getter @Setter
		private String host = "127.0.0.1";
		
		@XmlAttribute
		@Getter @Setter
		private int port = 502;
		
		@XmlAttribute
		@Getter @Setter
		private int interval = 1000;
		
		@XmlAttribute
		@Getter @Setter
		private long timeout = 2000;

		@XmlElement
		@Getter @Setter
		private List<ValueEntry> values = Lists.newArrayList();
		
	}
	
	@XmlAccessorType(XmlAccessType.FIELD)
	@XmlRootElement
	@NoArgsConstructor
	public static class ValueEntry {
		
		@XmlAttribute
		@Getter @Setter
		private String valueKey = "KEY" + System.currentTimeMillis();
		
		@XmlAttribute
		@Getter @Setter
		private String valueType = "UNSET";		
		
		@XmlElement
		@Getter @Setter
		private String parameters = "UNSET";	
		
		/*
		@XmlElement
		@Getter @Setter
		public List<HandleParameter> parameters = Lists.newArrayList();  
		*/
		
	}
	
	/*
	@XmlAccessorType(XmlAccessType.FIELD)
	@XmlRootElement
	@NoArgsConstructor
	public static class HandleParameter {
		@Getter @Setter
        private String key;  
		@Getter @Setter
        private String value;  
	}
	*/
	
	public static String key(FetcherEntry fe, ValueEntry ve) {
		return fe.getName() + "." + ve.getValueKey();
	}
	
	public static class ParameterManager {
		
		static Splitter splitter1 = Splitter.on(',').trimResults().omitEmptyStrings();
		static Splitter splitter2 = Splitter.on('=').trimResults().omitEmptyStrings();
		
		Map<String, String> map = Maps.newHashMap();
		
		public static ParameterManager at(ValueEntry ve) {
			return new ParameterManager(ve.getParameters());
		}
		
		public static ParameterManager at(String parameters) {
			return new ParameterManager(parameters);
		}
		
		private ParameterManager(String parameters) {
			parse(parameters);
		}
		
		private void parse(String source) {
			
			Iterable<String> kvs = splitter1.split(source);
			for(String kv : kvs) {
				
				List<String> kvList = splitter2.splitToList(kv);
				if(kvList.size() > 1) {
					String key = kvList.get(0);
					String value = kvList.get(1);
					map.put(key, value);
				}
			}
		}
		
		public String getOrDefault(String key, String def) {
			String result = map.get(key);
			return result != null ? result : def;
		}
		
		public int getOrDefault(String key, int def) {
			
			try {
				String s = getOrDefault(key, null);
				return Integer.parseInt(s);
			} catch(Exception e) {
				return def;
			}
			
		}
		
		public long getOrDefault(String key, long def) {
			
			try {
				String s = getOrDefault(key, null);
				return Long.parseLong(s);
			} catch(Exception e) {
				return def;
			}
			
		}
		
		public double getOrDefault(String key, double def) {
			
			try {
				String s = getOrDefault(key, null);
				return Double.parseDouble(s);
			} catch(Exception e) {
				return def;
			}
			
		}
		
		public float getOrDefault(String key, float def) {
			
			try {
				String s = getOrDefault(key, null);
				return Float.parseFloat(s);
			} catch(Exception e) {
				return def;
			}
			
		}
		
		
		public void setValue(String key, String value) {
			
			if(Strings.isNullOrEmpty(key) || Strings.isNullOrEmpty(value))
				return;
			
			map.put(key, value);
			
		}
		
		
		@Override
		public String toString() {
			
			StringBuilder sb = new StringBuilder();
			
			map.forEach((k, v)-> {
				if(sb.length() > 0) {
					sb.append(",");
				}
				sb.append(k);
				sb.append("=");
				sb.append(v);
			});
			
			
			return sb.toString();
		}
		
	}

}
